home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / lisp / stk-3.002 / stk-3 / STk-3.1 / Tk / generic / tkVisual.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-31  |  15.6 KB  |  541 lines

  1. /* 
  2.  * tkVisual.c --
  3.  *
  4.  *    This file contains library procedures for allocating and
  5.  *    freeing visuals and colormaps.  This code is based on a
  6.  *    prototype implementation by Paul Mackerras.
  7.  *
  8.  * Copyright (c) 1994 The Regents of the University of California.
  9.  * Copyright (c) 1994-1995 Sun Microsystems, Inc.
  10.  *
  11.  * See the file "license.terms" for information on usage and redistribution
  12.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  13.  *
  14.  * SCCS: @(#) tkVisual.c 1.18 96/02/15 18:53:08
  15.  */
  16.  
  17. #include "tkInt.h"
  18. #include "tkPort.h"
  19.  
  20. /*
  21.  * The table below maps from symbolic names for visual classes
  22.  * to the associated X class symbols.
  23.  */
  24.  
  25. typedef struct VisualDictionary {
  26.     char *name;            /* Textual name of class. */
  27.     int minLength;        /* Minimum # characters that must be
  28.                  * specified for an unambiguous match. */
  29.     int class;            /* X symbol for class. */
  30. } VisualDictionary;
  31. static VisualDictionary visualNames[] = {
  32.     {"best",        1,    0},
  33.     {"directcolor",    2,    DirectColor},
  34.     {"grayscale",    1,    GrayScale},
  35.     {"greyscale",    1,    GrayScale},
  36.     {"pseudocolor",    1,    PseudoColor},
  37.     {"staticcolor",    7,    StaticColor},
  38.     {"staticgray",    7,    StaticGray},
  39.     {"staticgrey",    7,    StaticGray},
  40.     {"truecolor",    1,    TrueColor},
  41.     {NULL,        0,    0},
  42. };
  43.  
  44. /*
  45.  * One of the following structures exists for each distinct non-default
  46.  * colormap allocated for a display by Tk_GetColormap.
  47.  */
  48.  
  49. struct TkColormap {
  50.     Colormap colormap;        /* X's identifier for the colormap. */
  51.     Visual *visual;        /* Visual for which colormap was
  52.                  * allocated. */
  53.     int refCount;        /* How many uses of the colormap are still
  54.                  * outstanding (calls to Tk_GetColormap
  55.                  * minus calls to Tk_FreeColormap). */
  56.     int shareable;        /* 0 means this colormap was allocated by
  57.                  * a call to Tk_GetColormap with "new",
  58.                  * implying that the window wants it all
  59.                  * for itself.  1 means that the colormap
  60.                  * was allocated as a default for a particular
  61.                  * visual, so it can be shared. */
  62.     struct TkColormap *nextPtr;    /* Next in list of colormaps for this display,
  63.                  * or NULL for end of list. */
  64. };
  65.  
  66. /*
  67.  *----------------------------------------------------------------------
  68.  *
  69.  * Tk_GetVisual --
  70.  *
  71.  *    Given a string identifying a particular kind of visual, this
  72.  *    procedure returns a visual and depth that matches the specification.
  73.  *
  74.  * Results:
  75.  *    The return value is normally a pointer to a visual.  If an
  76.  *    error occurred in looking up the visual, NULL is returned and
  77.  *    an error message is left in interp->result.  The depth of the
  78.  *    visual is returned to *depthPtr under normal returns.  If
  79.  *    colormapPtr is non-NULL, then this procedure also finds a
  80.  *    suitable colormap for use with the visual in tkwin, and it
  81.  *    returns that colormap in *colormapPtr unless an error occurs.
  82.  *
  83.  * Side effects:
  84.  *    A new colormap may be allocated.
  85.  *
  86.  *----------------------------------------------------------------------
  87.  */
  88.  
  89. Visual *
  90. Tk_GetVisual(interp, tkwin, string, depthPtr, colormapPtr)
  91.     Tcl_Interp *interp;            /* Interpreter to use for error
  92.                      * reporting. */
  93.     Tk_Window tkwin;            /* Window in which visual will be
  94.                      * used. */
  95.     char *string;            /* String describing visual.  See
  96.                      * manual entry for details. */
  97.     int *depthPtr;            /* The depth of the returned visual
  98.                      * is stored here. */
  99.     Colormap *colormapPtr;        /* If non-NULL, then a suitable
  100.                      * colormap for visual is placed here.
  101.                      * This colormap must eventually be
  102.                      * freed by calling Tk_FreeColormap. */
  103. {
  104.     Tk_Window tkwin2;
  105.     XVisualInfo template, *visInfoList, *bestPtr;
  106.     long mask;
  107.     Visual *visual;
  108.     int length, c, numVisuals, prio, bestPrio, i;
  109.     char *p;
  110.     VisualDictionary *dictPtr;
  111.     TkColormap *cmapPtr;
  112.     TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
  113.  
  114.     /*
  115.      * Parse string and set up a template for use in searching for
  116.      * an appropriate visual.
  117.      */
  118.  
  119.     c = string[0];
  120.     if (c == '.') {
  121.     /*
  122.      * The string must be a window name.  If the window is on the
  123.      * same screen as tkwin, then just use its visual.  Otherwise
  124.      * use the information about the visual as a template for the
  125.      * search.
  126.      */
  127.  
  128.     tkwin2 = Tk_NameToWindow(interp, string, tkwin);
  129.     if (tkwin2 == NULL) {
  130.         return NULL;
  131.     }
  132.     visual = Tk_Visual(tkwin2);
  133.     if (Tk_Screen(tkwin) == Tk_Screen(tkwin2)) {
  134.         *depthPtr = Tk_Depth(tkwin2);
  135.         if (colormapPtr != NULL) {
  136.         /*
  137.          * Use the colormap from the other window too (but be sure
  138.          * to increment its reference count if it's one of the ones
  139.          * allocated here).
  140.          */
  141.  
  142.         *colormapPtr = Tk_Colormap(tkwin2);
  143.         for (cmapPtr = dispPtr->cmapPtr; cmapPtr != NULL;
  144.             cmapPtr = cmapPtr->nextPtr) {
  145.             if (cmapPtr->colormap == *colormapPtr) {
  146.             cmapPtr->refCount += 1;
  147.             break;
  148.             }
  149.         }
  150.         }
  151.         return visual;
  152.     }
  153.     template.depth = Tk_Depth(tkwin2);
  154.     template.class = visual->class;
  155.     template.red_mask = visual->red_mask;
  156.     template.green_mask = visual->green_mask;
  157.     template.blue_mask = visual->blue_mask;
  158.     template.colormap_size = visual->map_entries;
  159.     template.bits_per_rgb = visual->bits_per_rgb;
  160.     mask = VisualDepthMask|VisualClassMask|VisualRedMaskMask
  161.         |VisualGreenMaskMask|VisualBlueMaskMask|VisualColormapSizeMask
  162.         |VisualBitsPerRGBMask;
  163.     } else if ((c == 0) || ((c == 'd') && (string[1] != 0)
  164.         && (strncmp(string, "default", strlen(string)) == 0))) {
  165.     /*
  166.      * Use the default visual for the window's screen.
  167.      */
  168.  
  169.     if (colormapPtr != NULL) {
  170.         *colormapPtr = DefaultColormapOfScreen(Tk_Screen(tkwin));
  171.     }
  172.     *depthPtr = DefaultDepthOfScreen(Tk_Screen(tkwin));
  173.     return DefaultVisualOfScreen(Tk_Screen(tkwin));
  174.     } else if (isdigit(UCHAR(c))) {
  175.     int visualId;
  176.  
  177.     /*
  178.     * This is a visual ID.
  179.     */
  180.  
  181.     if (Tcl_GetInt(interp, string, &visualId) == TCL_ERROR) {
  182.         Tcl_ResetResult(interp);
  183.         Tcl_AppendResult(interp, "bad X identifier for visual: ",
  184.             string, "\"", (char *) NULL);
  185.         return NULL;
  186.     }
  187.     template.visualid = visualId;
  188.     mask = VisualIDMask;
  189.     } else {
  190.     /*
  191.      * Parse the string into a class name (or "best") optionally
  192.      * followed by whitespace and a depth.
  193.      */
  194.  
  195.     for (p = string; *p != 0; p++) {
  196.         if (isspace(UCHAR(*p)) || isdigit(UCHAR(*p))) {
  197.         break;
  198.         }
  199.     }
  200.     length = p - string;
  201.     template.class = -1;
  202.     for (dictPtr = visualNames; dictPtr->name != NULL; dictPtr++) {
  203.         if ((dictPtr->name[0] == c) && (length >= dictPtr->minLength)
  204.             && (strncmp(string, dictPtr->name,
  205.             (size_t) length) == 0)) {
  206.         template.class = dictPtr->class;
  207.         break;
  208.         }
  209.     }
  210.     if (template.class == -1) {
  211.         Tcl_AppendResult(interp, "unknown or ambiguous visual name \"",
  212.             string, "\": class must be ", (char *) NULL);
  213.         for (dictPtr = visualNames; dictPtr->name != NULL; dictPtr++) {
  214.         Tcl_AppendResult(interp, dictPtr->name, ", ", (char *) NULL);
  215.         }
  216.         Tcl_AppendResult(interp, "or default", (char *) NULL);
  217.         return NULL;
  218.     }
  219.     while (isspace(UCHAR(*p))) {
  220.         p++;
  221.     }
  222.     if (*p == 0) {
  223.         template.depth = 10000;
  224.     } else {
  225.         if (Tcl_GetInt(interp, p, &template.depth) != TCL_OK) {
  226.         return NULL;
  227.         }
  228.     }
  229.     if (c == 'b') {
  230.         mask = 0;
  231.     } else {
  232.         mask = VisualClassMask;
  233.     }
  234.     }
  235.  
  236.     /*
  237.      * Find all visuals that match the template we've just created,
  238.      * and return an error if there are none that match.
  239.      */
  240.  
  241.     template.screen = Tk_ScreenNumber(tkwin);
  242.     mask |= VisualScreenMask;
  243.     visInfoList = XGetVisualInfo(Tk_Display(tkwin), mask, &template,
  244.         &numVisuals);
  245.     if (visInfoList == NULL) {
  246.     interp->result = "couldn't find an appropriate visual";
  247.     return NULL;
  248.     }
  249.  
  250.     /*
  251.      * Search through the visuals that were returned to find the best
  252.      * one.  The choice is based on the following criteria, in decreasing
  253.      * order of importance:
  254.      *
  255.      * 1. Depth: choose a visual with exactly the desired depth,
  256.      *      else one with more bits than requested but as few bits
  257.      *      as possible, else one with fewer bits but as many as
  258.      *    possible.
  259.      * 2. Class: some visual classes are more desirable than others;
  260.      *    pick the visual with the most desirable class.
  261.      * 3. Default: the default visual for the screen gets preference
  262.      *    over other visuals, all else being equal.
  263.      */
  264.  
  265.     bestPrio = 0;
  266.     bestPtr = NULL;
  267.     for (i = 0; i < numVisuals; i++) {
  268.     switch (visInfoList[i].class) {
  269.         case DirectColor:    prio = 5; break;
  270.         case GrayScale:    prio = 1; break;
  271.         case PseudoColor:    prio = 7; break;
  272.         case StaticColor:    prio = 3; break;
  273.         case StaticGray:    prio = 1; break;
  274.         case TrueColor:    prio = 5; break;
  275.         default:        prio = 0; break;
  276.     }
  277.     if (visInfoList[i].visual
  278.         == DefaultVisualOfScreen(Tk_Screen(tkwin))) {
  279.         prio++;
  280.     }
  281.     if (bestPtr == NULL) {
  282.         goto newBest;
  283.     }
  284.     if (visInfoList[i].depth < bestPtr->depth) {
  285.         if (visInfoList[i].depth >= template.depth) {
  286.         goto newBest;
  287.         }
  288.     } else if (visInfoList[i].depth > bestPtr->depth) {
  289.         if (bestPtr->depth < template.depth) {
  290.         goto newBest;
  291.         }
  292.     } else {
  293.         if (prio > bestPrio) {
  294.         goto newBest;
  295.         }
  296.     }
  297.     continue;
  298.  
  299.     newBest:
  300.     bestPtr = &visInfoList[i];
  301.     bestPrio = prio;
  302.     }
  303.     *depthPtr = bestPtr->depth;
  304.     visual = bestPtr->visual;
  305.     XFree((char *) visInfoList);
  306.  
  307.     /*
  308.      * If we need to find a colormap for this visual, do it now.
  309.      * If the visual is the default visual for the screen, then
  310.      * use the default colormap.  Otherwise search for an existing
  311.      * colormap that's shareable.  If all else fails, create a new
  312.      * colormap.
  313.      */
  314.  
  315.     if (colormapPtr != NULL) {
  316.     if (visual == DefaultVisualOfScreen(Tk_Screen(tkwin))) {
  317.         *colormapPtr = DefaultColormapOfScreen(Tk_Screen(tkwin));
  318.     } else {
  319.         for (cmapPtr = dispPtr->cmapPtr; cmapPtr != NULL;
  320.             cmapPtr = cmapPtr->nextPtr) {
  321.         if (cmapPtr->shareable && (cmapPtr->visual == visual)) {
  322.             *colormapPtr = cmapPtr->colormap;
  323.             cmapPtr->refCount += 1;
  324.             goto done;
  325.         }
  326.         }
  327.         cmapPtr = (TkColormap *) ckalloc(sizeof(TkColormap));
  328.         cmapPtr->colormap = XCreateColormap(Tk_Display(tkwin),
  329.             RootWindowOfScreen(Tk_Screen(tkwin)), visual,
  330.             AllocNone);
  331.         cmapPtr->visual = visual;
  332.         cmapPtr->refCount = 1;
  333.         cmapPtr->shareable = 1;
  334.         cmapPtr->nextPtr = dispPtr->cmapPtr;
  335.         dispPtr->cmapPtr = cmapPtr;
  336.         *colormapPtr = cmapPtr->colormap;
  337.     }
  338.     }
  339.  
  340.     done:
  341.     return visual;
  342. }
  343.  
  344. /*
  345.  *----------------------------------------------------------------------
  346.  *
  347.  * Tk_GetColormap --
  348.  *
  349.  *    Given a string identifying a colormap, this procedure finds
  350.  *    an appropriate colormap.
  351.  *
  352.  * Results:
  353.  *    The return value is normally the X resource identifier for the
  354.  *    colormap.  If an error occurs, None is returned and an error
  355.  *    message is placed in interp->result.
  356.  *
  357.  * Side effects:
  358.  *    A reference count is incremented for the colormap, so
  359.  *    Tk_FreeColormap must eventually be called exactly once for
  360.  *    each call to Tk_GetColormap.
  361.  *
  362.  *----------------------------------------------------------------------
  363.  */
  364.  
  365. Colormap
  366. Tk_GetColormap(interp, tkwin, string)
  367.     Tcl_Interp *interp;            /* Interpreter to use for error
  368.                      * reporting. */
  369.     Tk_Window tkwin;            /* Window where colormap will be
  370.                      * used. */
  371.     char *string;            /* String that identifies colormap:
  372.                      * either "new" or the name of
  373.                      * another window. */
  374. {
  375.     Colormap colormap;
  376.     TkColormap *cmapPtr;
  377.     TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
  378.     Tk_Window other;
  379.  
  380.     /*
  381.      * Allocate a new colormap, if that's what is wanted.
  382.      */
  383.  
  384.     if (strcmp(string, "new") == 0) {
  385.     cmapPtr = (TkColormap *) ckalloc(sizeof(TkColormap));
  386.     cmapPtr->colormap = XCreateColormap(Tk_Display(tkwin),
  387.         RootWindowOfScreen(Tk_Screen(tkwin)), Tk_Visual(tkwin),
  388.         AllocNone);
  389.     cmapPtr->visual = Tk_Visual(tkwin);
  390.     cmapPtr->refCount = 1;
  391.     cmapPtr->shareable = 0;
  392.     cmapPtr->nextPtr = dispPtr->cmapPtr;
  393.     dispPtr->cmapPtr = cmapPtr;
  394.     return cmapPtr->colormap;
  395.     }
  396.  
  397.     /*
  398.      * Use a colormap from an existing window.  It must have the same
  399.      * visual as tkwin (which means, among other things, that the
  400.      * other window must be on the same screen).
  401.      */
  402.  
  403.     other = Tk_NameToWindow(interp, string, tkwin);
  404.     if (other == NULL) {
  405.     return None;
  406.     }
  407.     if (Tk_Screen(other) != Tk_Screen(tkwin)) {
  408.     Tcl_AppendResult(interp, "can't use colormap for ", string,
  409.         ": not on same screen", (char *) NULL);
  410.     return None;
  411.     }
  412.     if (Tk_Visual(other) != Tk_Visual(tkwin)) {
  413.     Tcl_AppendResult(interp, "can't use colormap for ", string,
  414.         ": incompatible visuals", (char *) NULL);
  415.     return None;
  416.     }
  417.     colormap = Tk_Colormap(other);
  418.  
  419.     /*
  420.      * If the colormap was a special one allocated by code in this file,
  421.      * increment its reference count.
  422.      */
  423.  
  424.     for (cmapPtr = dispPtr->cmapPtr; cmapPtr != NULL;
  425.         cmapPtr = cmapPtr->nextPtr) {
  426.     if (cmapPtr->colormap == colormap) {
  427.         cmapPtr->refCount += 1;
  428.     }
  429.     }
  430.     return colormap;
  431. }
  432.  
  433. /*
  434.  *----------------------------------------------------------------------
  435.  *
  436.  * Tk_FreeColormap --
  437.  *
  438.  *    This procedure is called to release a colormap that was
  439.  *    previously allocated by Tk_GetColormap.
  440.  *
  441.  * Results:
  442.  *    None.
  443.  *
  444.  * Side effects:
  445.  *    The colormap's reference count is decremented.  If this was the
  446.  *    last reference to the colormap, then the colormap is freed.
  447.  *
  448.  *----------------------------------------------------------------------
  449.  */
  450.  
  451. void
  452. Tk_FreeColormap(display, colormap)
  453.     Display *display;            /* Display for which colormap was
  454.                      * allocated. */
  455.     Colormap colormap;            /* Colormap that is no longer needed.
  456.                      * Must have been returned by previous
  457.                      * call to Tk_GetColormap, or
  458.                      * preserved by a previous call to
  459.                      * Tk_PreserveColormap. */
  460. {
  461.     TkDisplay *dispPtr;
  462.     TkColormap *cmapPtr, *prevPtr;
  463.  
  464.     /*
  465.      * Find Tk's information about the display, then see if this
  466.      * colormap is a non-default one (if it's a default one, there
  467.      * won't be an entry for it in the display's list).
  468.      */
  469.  
  470.     dispPtr = TkGetDisplay(display);
  471.     if (dispPtr == NULL) {
  472.     panic("unknown display passed to Tk_FreeColormap");
  473.     }
  474.     for (prevPtr = NULL, cmapPtr = dispPtr->cmapPtr; cmapPtr != NULL;
  475.         prevPtr = cmapPtr, cmapPtr = cmapPtr->nextPtr) {
  476.     if (cmapPtr->colormap == colormap) {
  477.         cmapPtr->refCount -= 1;
  478.         if (cmapPtr->refCount == 0) {
  479.         XFreeColormap(display, colormap);
  480.         if (prevPtr == NULL) {
  481.             dispPtr->cmapPtr = cmapPtr->nextPtr;
  482.         } else {
  483.             prevPtr->nextPtr = cmapPtr->nextPtr;
  484.         }
  485.         ckfree((char *) cmapPtr);
  486.         }
  487.         return;
  488.     }
  489.     } 
  490. }
  491.  
  492. /*
  493.  *----------------------------------------------------------------------
  494.  *
  495.  * Tk_PreserveColormap --
  496.  *
  497.  *    This procedure is called to indicate to Tk that the specified
  498.  *    colormap is being referenced from another location and should
  499.  *    not be freed until all extra references are eliminated.  The
  500.  *    colormap must have been returned by Tk_GetColormap.
  501.  *
  502.  * Results:
  503.  *    None.
  504.  *
  505.  * Side effects:
  506.  *    The colormap's reference count is incremented, so
  507.  *    Tk_FreeColormap must eventually be called exactly once for
  508.  *    each call to Tk_PreserveColormap.
  509.  *
  510.  *----------------------------------------------------------------------
  511.  */
  512.  
  513. void
  514. Tk_PreserveColormap(display, colormap)
  515.     Display *display;            /* Display for which colormap was
  516.                      * allocated. */
  517.     Colormap colormap;            /* Colormap that should be
  518.                      * preserved. */
  519. {
  520.     TkDisplay *dispPtr;
  521.     TkColormap *cmapPtr, *prevPtr;
  522.  
  523.     /*
  524.      * Find Tk's information about the display, then see if this
  525.      * colormap is a non-default one (if it's a default one, there
  526.      * won't be an entry for it in the display's list).
  527.      */
  528.  
  529.     dispPtr = TkGetDisplay(display);
  530.     if (dispPtr == NULL) {
  531.     panic("unknown display passed to Tk_PreserveColormap");
  532.     }
  533.     for (prevPtr = NULL, cmapPtr = dispPtr->cmapPtr; cmapPtr != NULL;
  534.         prevPtr = cmapPtr, cmapPtr = cmapPtr->nextPtr) {
  535.     if (cmapPtr->colormap == colormap) {
  536.         cmapPtr->refCount += 1;
  537.         return;
  538.     }
  539.     } 
  540. }
  541.